#include "ChatManager.h"

#include "XMPPConnection.h"
#include "PacketCollector.h"
#include "PacketInterceptor.h"
#include "MessageListener.h"
#include "Chat.h"
#include "ChatManagerListener.h"

#include <packet/Message.h>

#include <filter/AndFilter.h>
#include <filter/ThreadFilter.h>
#include <filter/FromContainsFilter.h>

#include <util/StringUtils.h>



std::string prefix = StringUtils::randomString(5);
long id = 0;

std::string ChatManager::nextID() {
	char temp[20];
	snprintf(temp, 20, "%ld", id);
	++id;
	return prefix + temp;
}

ChatManager::ChatManager(XMPPConnection * connection) :
	connection(connection)
{
    PacketFilter * filter = new MPacketFilter();
    // Add a listener for all message packets so that we can deliver errant
    // messages to the best Chat instance available.
	PacketListener * deliverPacketListener = new DeliverPacketListener(this);
    connection->addPacketListener(deliverPacketListener, filter);
}

Chat * ChatManager::createChat(std::string & userJID, MessageListener * listener) {
	std::string threadID;
    do  {
    	threadID = nextID();
    } while (threadChats[threadID] != NULL);

    return createChat(userJID, threadID, listener);
}

Chat * ChatManager::createChat(std::string userJID, std::string thread, MessageListener * listener) {
    if(thread.empty()) {
    	thread = nextID();
    }
    Chat * chat = threadChats[thread];
    if(chat != NULL) {
    	//throw new IllegalArgumentException("ThreadID is already used");
    }
    chat = createChat(userJID, thread, true);
    chat->addMessageListener(listener);
    return chat;
}

Chat * ChatManager::createChat(std::string userJID, std::string threadID, bool createdLocally) {
    Chat * chat = new Chat(this, userJID, threadID);
    threadChats[threadID] = chat;
    jidChats[userJID] = chat;

    for(std::vector<ChatManagerListener*>::iterator it = chatManagerListeners.begin();
			it != chatManagerListeners.end(); ++it) {
    	(*it)->chatCreated(chat, createdLocally);
    }

    return chat;
}

Chat * ChatManager::createChat(Message * message) {
	std::string threadID = message->getThread();
    if(threadID.empty()) {
    	threadID = nextID();
    }
	std::string userJID = message->getFrom();

    return createChat(userJID, threadID, false);
}

Chat * ChatManager::getUserChat(std::string userJID) {
    return jidChats[userJID];
}

Chat * ChatManager::getThreadChat(std::string thread) {
    return threadChats[thread];
}

void ChatManager::addChatListener(ChatManagerListener * listener) {
    chatManagerListeners.push_back(listener);
}

void ChatManager::removeChatListener(ChatManagerListener * listener) {
	std::vector<ChatManagerListener*>::iterator it = std::find( chatManagerListeners.begin(), 
			chatManagerListeners.end(), listener); 
	delete *it;
	chatManagerListeners.erase(it);
}

std::vector<ChatManagerListener*> ChatManager::getChatListeners() {
    return chatManagerListeners;
}

void ChatManager::deliverMessage(Chat * chat, Message * message) {
    // Here we will run any interceptors
    chat->deliver(message);
}

void ChatManager::sendMessage(Chat * chat, Message * message) {
    for(std::map<PacketInterceptor*, PacketFilter*>::iterator it = interceptors.begin();
			it != interceptors.end(); ++it ) {
    	PacketFilter * filter = it->second;
    	if(filter != NULL && filter->accept(message)) {
			PacketInterceptor * packetInterceptor = it->first;
    		packetInterceptor->interceptPacket(message);
    	}
    }
    // Ensure that messages being sent have a proper FROM value
    if (message->getFrom().empty()) {
    message->setFrom(connection->getUser());
    }
    connection->sendPacket(message);
}

PacketCollector * ChatManager::createPacketCollector(Chat * chat) {
    return connection->createPacketCollector(new AndFilter(new ThreadFilter(chat->getThreadID()), 
				new FromContainsFilter(chat->getParticipant())));
}

void ChatManager::addOutgoingMessageInterceptor(PacketInterceptor * packetInterceptor) {
    addOutgoingMessageInterceptor(packetInterceptor, NULL);
}

void ChatManager::addOutgoingMessageInterceptor(PacketInterceptor * packetInterceptor, PacketFilter * filter) {
	if (packetInterceptor != NULL) {
    	interceptors[packetInterceptor] = filter;
    }
}

bool ChatManager::MPacketFilter::accept(Packet * packet) {
	Message * message = dynamic_cast<Message *>(packet);
	Message::TYPE messageType = message->getType();
	return messageType != Message::GROUPCHAT &&
		messageType != Message::HEADLINE;
}

void ChatManager::DeliverPacketListener::processPacket(Packet * packet) {
	Chat * chat = NULL;
	Message * message = dynamic_cast<Message *>(packet);
	if(message->getThread().empty()) {
		chat = manager->getUserChat(StringUtils::parseBareAddress(message->getFrom()));
	} else {
		chat = manager->getThreadChat(message->getThread());
		if(chat == NULL) {
			chat = manager->getUserChat(StringUtils::parseBareAddress(message->getFrom()));
		}
	}
	if(chat == NULL) {
		chat = manager->createChat(message);
	}
	manager->deliverMessage(chat, message);
}

